package expression.integer;

import java.util.ArrayList;
import java.util.List;

import choco.integer.IntDomainVar;
import choco.integer.IntExp;
import core.Predicate;
import core.Universe;

public abstract class IntVarExpr extends IntExpr {
	public static int MAX_VALUE = 1000000;
	public static int MIN_VALUE = -1000000;
	public static int MAX_ENUM = 100;

	protected String name;
	protected IntDomainVar variable;
	protected List<Predicate> predicates;
	protected List<IntVarExpr> varDependencies;
	protected List<Predicate> predDependencies;

	public IntVarExpr(Universe u, String n) {
		super(u);
		u.addVariable(this);

		name = n;
		
		predicates = new ArrayList<Predicate>();
		varDependencies = new ArrayList<IntVarExpr>();
		predDependencies = new ArrayList<Predicate>();
	}
	
	public String getName() {
		return name;
	}

	public IntDomainVar getVariable() {
		return variable;
	}

	public List<Predicate> getPredicates() {
		return predicates;
	}
	
	public List<IntVarExpr> getVarDepencies() {
		return varDependencies;
	}
	
	public List<Predicate> getPredDepencies() {
		return predDependencies;
	}
	
	public void addPredicate(Predicate p) {
		if (!predicates.contains(p))
			predicates.add(p);
	}
	
	protected void initPredDep() {
		// predDependencies
		List<Predicate> newPred = new ArrayList<Predicate>();
		newPred.addAll(getPredicates());
		
		while (newPred.size() > 0) {
			Predicate pred = newPred.get(0);
			newPred.remove(0);
			predDependencies.add(pred);
			
			for (IntVarExpr v: pred.getVariables()) {
				for (Predicate p: v.getPredicates()) {
					if ((p != pred) && (!newPred.contains(p)) && (!predDependencies.contains(p))) {
						newPred.add(p);
					}
				}
			}
		}		
	}
	
	protected void initVarDep() {
		// varDpendencies
		for (Predicate p: predDependencies) {
			for (IntVarExpr v: p.getVariables()) {
				if ((v != this) && (!varDependencies.contains(v))) {
					varDependencies.add(v);
				}
			}
		}		
	}
	
	public void init() {
		initPredDep();
		initVarDep();
	}
	
	public abstract void reset();
	
	public List<IntVarExpr> getVariables() {
		List<IntVarExpr> vars = new ArrayList<IntVarExpr>();
		vars.add(this);
		
		return vars;
	}
	
	public IntExp intExp() {
		return variable;
	}	
}
